package org.jeecg.modules.api.wlhy.app.utils;

import com.alibaba.fastjson.JSONObject;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

public class SM2Util {


    private static final String publicKey = "04B0C0BB347F8F86F674FC0B6BC71BC37C9AF90872E93D8D0483F0BBCFC1E6C6BE8B61825EC90918AE45CC540B8F6BBF1DDCC6BDB38549628FFA6313003547EF34";

    //数据加密
    public static String encrypt( String data) throws IOException {
        return encrypt(Util.hexToByte(publicKey), data.getBytes(StandardCharsets.UTF_8));
    }
    //数据加密
    public static String encrypt(byte[] publicKey, byte[] data) throws IOException {
        if (publicKey == null || publicKey.length == 0) {
            return null;
        }

        if (data == null || data.length == 0) {
            return null;
        }

        byte[] source = new byte[data.length];
        System.arraycopy(data, 0, source, 0, data.length);

        Cipher cipher = new Cipher();
        SM2 sm2 = SM2.Instance();
        ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);

        ECPoint c1 = cipher.Init_enc(sm2, userKey);
        cipher.Encrypt(source);
        byte[] c3 = new byte[32];
        cipher.Dofinal(c3);

//      System.out.println("C1 " + Util.byteToHex(c1.getEncoded()));
//      System.out.println("C2 " + Util.byteToHex(source));
//      System.out.println("C3 " + Util.byteToHex(c3));
        //C1 C2 C3拼装成加密字串
        return Util.byteToHex(c1.getEncoded()) + Util.byteToHex(source) + Util.byteToHex(c3);

    }

    public static String decrypt(String privateKey, String encryptedData)  {
        byte[] decrypt = decrypt(Util.hexToByte(privateKey), Util.hexToByte(encryptedData));
        return new String(decrypt, StandardCharsets.UTF_8);
    }

    //数据解密
    public static byte[] decrypt(byte[] privateKey, byte[] encryptedData)  {
        //加密字节数组转换为十六进制的字符串 长度变为encryptedData.length * 2
        String data = Util.byteToHex(encryptedData);
        /***分解加密字串
         * （C1 = C1标志位2位 + C1实体部分128位 = 130）
         * （C3 = C3实体部分64位  = 64）
         * （C2 = encryptedData.length * 2 - C1长度  - C2长度）
         */
        byte[] c1Bytes = Util.hexToByte(data.substring(0, 130));
        int c2Len = encryptedData.length - 97;
        byte[] c2 = Util.hexToByte(data.substring(130, 130 + 2 * c2Len));
        byte[] c3 = Util.hexToByte(data.substring(130 + 2 * c2Len, 194 + 2 * c2Len));

        SM2 sm2 = SM2.Instance();
        BigInteger userD = new BigInteger(1, privateKey);

        //通过C1实体字节来生成ECPoint
        ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes);
        Cipher cipher = new Cipher();
        cipher.Init_dec(userD, c1);
        cipher.Decrypt(c2);
        cipher.Dofinal(c3);

        //返回解密结果
        return c2;
    }


//    public static StringKeyPair generateStringKeyPair() {
//        SM2 sm2 = SM2.Instance();
//        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();
//        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();
//        ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();
//        BigInteger privateKey = ecpriv.getD();
//        ECPoint publicKey = ecpub.getQ();
//
//        StringKeyPair stringKeyPair = new StringKeyPair();
//        stringKeyPair.setPublicKey(Util.byteToHex(publicKey.getEncoded()));
//        stringKeyPair.setPrivateKey(Util.byteToHex(privateKey.toByteArray()));
//        return stringKeyPair;
//    }

    public static Map<String, String> generateKeyPair()
    {
        Map<String, String> keys = new HashMap();
        SM2 sm2 = SM2.Instance();
        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();
        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters)key.getPrivate();
        ECPublicKeyParameters ecpub = (ECPublicKeyParameters)key.getPublic();
        BigInteger privateKey = ecpriv.getD();
        ECPoint publicKey = ecpub.getQ();

//        System.out.println("公钥: " + Util.byteToHex(publicKey.getEncoded()));
//        System.out.println("私钥: " + Util.byteToHex(privateKey.toByteArray()));
        keys.put("public_key_name", Util.byteToHex(publicKey.getEncoded()));
        keys.put("private_key_name", Util.byteToHex(privateKey.toByteArray()));

        return keys;
    }


    public static byte[] decrypt132(byte[] privateKey, byte[] encryptedData)
            throws IOException
    {
        if ((privateKey == null) || (privateKey.length == 0)) {
            return null;
        }
        if ((encryptedData == null) || (encryptedData.length == 0)) {
            return null;
        }
        String data = Util.byteToHex(encryptedData);





        byte[] c1Bytes = Util.hexToByte(data.substring(0, 130));
        int c2Len = encryptedData.length - 97;
        byte[] c3 = Util.hexToByte(data.substring(130, 194));
        byte[] c2 = Util.hexToByte(data.substring(194));


        SM2 sm2 = SM2.Instance();
        BigInteger userD = new BigInteger(1, privateKey);


        ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes);
        Cipher cipher = new Cipher();
        cipher.Init_dec(userD, c1);
        cipher.Decrypt(c2);
        cipher.Dofinal(c3);


        return c2;
    }

    public static String encrypt132(byte[] data, byte[] publicKey)
            throws IOException
    {
        if ((publicKey == null) || (publicKey.length == 0)) {
            return null;
        }
        if ((data == null) || (data.length == 0)) {
            return null;
        }
        byte[] source = new byte[data.length];
        System.arraycopy(data, 0, source, 0, data.length);

        Cipher cipher = new Cipher();
        SM2 sm2 = SM2.Instance();
        ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);

        ECPoint c1 = cipher.Init_enc(sm2, userKey);
        cipher.Encrypt(source);
        byte[] c3 = new byte[32];
        cipher.Dofinal(c3);

        return Util.byteToHex(c1.getEncoded()) + Util.byteToHex(c3) + Util.byteToHex(source);
    }


    public static String decryptECB(String sSrc, String aesKey)
            throws Exception
    {
        try
        {
            byte[] raw = aesKey.getBytes("ASCII");
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(javax.crypto.Cipher.DECRYPT_MODE, skeySpec);

            byte[] encrypted1 = new BASE64Decoder().decodeBuffer(sSrc);
            byte[] original = cipher.doFinal(encrypted1);
            return new String(original, "utf-8");
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public static String encryptECB(String sSrc, String aesKey)
            throws Exception
    {
        try
        {
            javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("AES/ECB/PKCS5Padding");
            byte[] raw = aesKey.getBytes();
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            cipher.init(1, skeySpec);
            byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8"));

            return new BASE64Encoder().encode(encrypted);
        }
        catch (Exception e) {}
        return null;
    }


    public static void main(String[] args) throws Exception {
        JSONObject json = new JSONObject();
        json.put("appId","uni.UNIA350809");
        json.put("appSecurity","OVUERG41M84BCIXEQXK5EZKGPX4OIXTEH6NQELUFEE2IJ8PCWA68BIQLPSZCXPID");
        json.put("enterpriseSenderCode","1391130108MA09WMFW72");
        json.put("randomPublicKey","04615088BD9DAF1480C3A6B647FBC364BD7E8B94A2902599B78A067740F53002A56564F9E3F1420C51D5C8B770F20C233F0D27C30828BFA68810DDB4489EE6BFED");
        String ss1 = HttpUtils.sendPost("http://111.205.202.84:8081/ministry-wlhy-exg/sdkPostion/initSendInfo",json.toJSONString());
        System.out.println(ss1);

        String info = new String(SM2Util.decrypt132(Util.hexToByte("566FF15D5FD7371E84D7E201E21B590993740E45D45D8DEA50D9CB8E205CD3EC"), Util.hexToByte("044667A6AC9EF118B31E3BD3CC5095289117F0FB646B1CFE0180F61629476BF81CF13CA3E26FB4538C6D2BE3ACCDE923F33391921F8D06F61B0E8D06C7C29D864D8568B19E88AA88149505724D59BC30094348FAB4E6C588E258A5B41034EE60F5CC15D231ABB141674E92C361202257CF")));
        System.out.println(info);
        String ss = decryptECB("u2W2j8qw5KKZA/H/vZZ4Wj2NlJe9rxiB0R2JHrLPaeuAK2PmaYfFJXR48GflmN3S5iUUH8WIP4l9Oq/UC7uGZQrBkVY8Su/ZrWomBDzLjWgNSQ3eVYbakhDaww54kMKuCxcpyI5nupvc9byGspS2BPfowi8wAG8PAmbTIynu4JJt9+F7sOh28/fWx2PBZpYq8kY3pnZ3swo2X9E4dUDEprX6FZCWXfcCE0wE2S3pb7b7Q9Y2BT05WfMxtibb1mrOEk4tt6Sk5601Y99u3HRqkD8pFKkko3s0LvhVK7XqJxyG+qRJFdMBOhS1nJU96ZR7zSs98gq1J5BtZfU/Y9qrzd6RsMts5fG/caqBrf+h5+M=","216eeaa715104487");
        System.out.println(ss);
    }

    public static void main1(String[] args) throws Exception {
//        //生成密钥对
//        StringKeyPair stringKeyPair = generateStringKeyPair();
//
//        // 国密规范正式私钥
//        String prik = stringKeyPair.getPrivateKey();
//        // 国密规范正式公钥
//        String pubk = stringKeyPair.getPublicKey();

        System.out.println("加密: ");
        String cipherText = encrypt("ext7oyku8gax2ua2");
        System.out.println(cipherText);
//        System.out.println("解密: ");
//        String decrypt = decrypt(prik, cipherText);
//        System.out.println(decrypt);


        //
        //String plainText = "1111121313";
        //byte[] sourceData = plainText.getBytes();
        //
        //System.out.println("加密: ");
        //String encrypt = SM2Util.encrypt(Util.hexToByte(pubk), sourceData);
        //System.out.println(encrypt);
        //System.out.println("解密: ");
        //plainText = new String(SM2Util.decrypt(Util.hexToByte(prik), Util.hexToByte(encrypt)));
        //System.out.println(plainText);

    }
}
